package com.block.datapush.special.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.block.account.enums.ActionTypeEnum;
import com.block.account.model.dto.EntryAccountDTO;
import com.block.account.service.impl.AccountItemSpecialServiceImpl;
import com.block.common.annotate.ExceptionLog;
import com.block.common.enums.InfoTypeEnum;
import com.block.common.exception.NotifyExceptionService;
import com.block.common.model.dto.CountInfoDTO;
import com.block.common.oss.config.OssAliConfig;
import com.block.common.oss.model.OssAuthInfoParam;
import com.block.common.oss.service.IOssService;
import com.block.common.service.IApplicationInfoService;
import com.block.common.service.IChannelCommonService;
import com.block.common.service.ICountCommonService;
import com.block.common.service.LogFactory;
import com.block.common.service.merchant.IMerchantThirdBaseInfoService;
import com.block.common.service.merchant.IMerchantThirdProtocolInfoService;
import com.block.datapush.model.dto.MerchantCountDTO;
import com.block.datapush.model.result.ApiPushResult;
import com.block.datapush.model.result.SpePushResut;
import com.block.datapush.service.IMemberPushOrderInfoService;
import com.block.datapush.special.enums.OrderStatusEnum;
import com.block.datapush.special.factory.InfoTypeFactory;
import com.block.datapush.special.service.*;
import com.block.db.entity.*;
import com.block.db.mapper.MemberExtInfoMapper;
import com.block.db.mapper.MemberPushOrderInfoMapper;
import com.block.db.mapper.MerchantThirdProtocolInfoMapper;
import com.block.db.mapper.SpecialCostomInfoMapper;
import com.block.sms.enums.UseTypeEnum;
import com.block.sms.service.ISmsRecordService;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URL;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 
 * @since 2022-09-15
 */
@Service
public class SpecialCostomInfoServiceImpl extends ServiceImpl<SpecialCostomInfoMapper, SpecialCostomInfo> implements ISpecialCostomInfoService {

    private static Logger log = LogFactory.getPushLog();

    // @Value("${market.protocol.hostUrl}")
    // private String protocolHostUrl;

    @Autowired
    ISpecialDataInfoService specialDataInfoService;
    @Autowired
    ISpecialCostomUserInfoService specialCostomUserInfoService;
    @Autowired
    ISpecialDataApiInfoService specialDataApiInfoService;
    @Autowired
    TransactionTemplate transactionTemplate;
    @Autowired
    ICountCommonService countCommonService;
    @Autowired
    AccountItemSpecialServiceImpl accountItemSpecialService;
    @Autowired
    IMemberPushOrderInfoService memberPushOrderInfoService;
    @Resource
    MemberPushOrderInfoMapper memberPushOrderInfoMapper;
    @Resource
    MemberExtInfoMapper memberExtInfoMapper;
    @Autowired
    ISmsRecordService smsRecordService;
    @Autowired
    NotifyExceptionService notifyExceptionService;

    @Autowired
    IChannelCommonService channelCommonService;
    @Autowired
    IApplicationInfoService applicationInfoService;
    @Autowired
    IOssService ossService;
    @Autowired
    OssAliConfig ossAliConfig;
    @Autowired
    IMerchantThirdBaseInfoService merchantThirdBaseInfoService;
    @Resource
    MerchantThirdProtocolInfoMapper merchantThirdProtocolInfoMapper;
    @Autowired
    ISpecialCostomCountInfoService specialCostomCountInfoService;

    @Value("${testMock.checkOrRegister:false}")
    private Boolean testMockCheckOrRegister;


    /**
     * 机构推送完成的逻辑
     * 将某个用户推送给某个机构
     * 根据商户设置的任务信息
     */
    @Override
    @ExceptionLog(key = "#costomId", bizType = "机构推送", bizName = "数据推送")
    public SpePushResut checkAndRegisterUser(SpecialCostomItemInfo itemInfo, MemberExtInfo memberExtInfo) throws Exception {

        SpePushResut spePushResut = new SpePushResut();

        SpecialCostomInfo costomInfo = this.getById(itemInfo.getInfoId());

        spePushResut.setInfoId(costomInfo.getId());
        spePushResut.setInfoType(costomInfo.getInfoType());
        spePushResut.setItemInfoId(itemInfo.getId());
        spePushResut.setInfoName(costomInfo.getName());
        spePushResut.setPriceAmount(itemInfo.getPriceAmount());
        spePushResut.setPushSuccess(false);


        ApiPushResult apiPushResult = InfoTypeFactory.getService(costomInfo.getInfoType()).checkAndRegisterUser(costomInfo, itemInfo, memberExtInfo);
        spePushResut.setPushSuccess(apiPushResult.isSuccess());
        spePushResut.setSettleFlag(apiPushResult.isSettleFlag());
        spePushResut.setSkipUrl(apiPushResult.getSkipUrl());
        spePushResut.setMessage(apiPushResult.getMessage());
        spePushResut.setExtData(apiPushResult.getOrderNo());

        log.info("【机构推送】推送完成【pushResult】{}【infoType】{}【itemId】{}【uid】{}",
                spePushResut.isPushSuccess(), costomInfo.getInfoType(), itemInfo.getId(), memberExtInfo.getUid());

        // 更新账户余额
        if (spePushResut.isSettleFlag()){
            /**
             * 机构收益统计
             */
            CountInfoDTO countInfoDTO = new CountInfoDTO(memberExtInfo.getChannelCode());
            countInfoDTO.setSpePushCount(1);
            countInfoDTO.setSpePushAmount(spePushResut.getPriceAmount());
            countCommonService.calculateDataInfo2(countInfoDTO);

            String billDateInfo = LocalDate.now().toString();

            EntryAccountDTO entryAccountDTO = new EntryAccountDTO();
            entryAccountDTO.setInfoId(String.valueOf(itemInfo.getInfoId()));
            entryAccountDTO.setBillDateInfo(billDateInfo);
            entryAccountDTO.setActionType(ActionTypeEnum.XH.getValue());
            entryAccountDTO.setChangeAmount(BigDecimal.ZERO.subtract(spePushResut.getPriceAmount()));
            entryAccountDTO.setExtData(spePushResut.getExtData());
            entryAccountDTO.setOperatorId("0");
            entryAccountDTO.setOperatorName("system");

            accountItemSpecialService.entryAccountInfo(entryAccountDTO);
        }
        // 返回更新结果
        return spePushResut;
    }


    /**
     * 机构撞库 生成订单信息
     */
    @Override
    @ExceptionLog(key = "#costomId", bizType = "机构检测推送", bizName = "数据检测推送")
    @Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
    public SpePushResut checkUser(SpecialCostomItemInfo itemInfo, MemberExtInfo memberExtInfo) throws Exception {

        // 查询用户信息
        SpecialCostomInfo costomInfo = this.baseMapper.getEntryByIdLock(itemInfo.getInfoId());
        // 保存订单信息
        MemberPushOrderInfo pushOrderInfo = memberPushOrderInfoService.savePushOrderInfo(itemInfo, costomInfo, memberExtInfo);

        // 构造推送信息
        SpePushResut spePushResut = new SpePushResut();
        spePushResut.setPushSuccess(false);

        spePushResut.setPushOrderNo(String.valueOf(pushOrderInfo.getId()));
        spePushResut.setInfoId(costomInfo.getId());
        spePushResut.setInfoType(costomInfo.getInfoType());
        spePushResut.setItemInfoId(itemInfo.getId());
        spePushResut.setInfoName(costomInfo.getName());
        spePushResut.setPriceAmount(itemInfo.getPriceAmount());

        // 返回机构的展示信息
        spePushResut.setCompanyName(costomInfo.getCompanyName());
        spePushResut.setCompanyLogo(costomInfo.getCompanyLogo());
        spePushResut.setProductName(costomInfo.getProductName());
        spePushResut.setMaxLoanAmount(costomInfo.getMaxLoanAmount());
        spePushResut.setMaxRate(costomInfo.getMaxRate());
        spePushResut.setMinRate(costomInfo.getMinRate());

        Long starttime = System.currentTimeMillis();

        MerchantCountDTO merchantCountDTO = new MerchantCountDTO(costomInfo.getId().intValue(), costomInfo.getName());
        merchantCountDTO.setCheckNumber(1);

        try {

            // 执行撞库操作
            ApiPushResult apiPushResult = InfoTypeFactory.getService(costomInfo.getInfoType())
                    .checkUser(costomInfo, pushOrderInfo, itemInfo, memberExtInfo);
            Long endtime = System.currentTimeMillis();
            log.info("【机构撞库】撞库完成【exectime】{}【apiPushResult】{}【infoType】{}【itemId】{}【uid】{}", endtime-starttime,
                    JSON.toJSONString(apiPushResult), costomInfo.getInfoType(), itemInfo.getId(), memberExtInfo.getUid());

            spePushResut.setPushSuccess(apiPushResult.isSuccess());
            spePushResut.setSkipUrl(apiPushResult.getSkipUrl());
            spePushResut.setMessage(apiPushResult.getMessage());

            // 更新推送订单信息
            MemberPushOrderInfo updateEntity = new MemberPushOrderInfo();
            updateEntity.setId(pushOrderInfo.getId());
            updateEntity.setPushId(apiPushResult.getOrderNo());
            if (apiPushResult.isSuccess()){
                merchantCountDTO.setCheckPassNumber(1);
                updateEntity.setStatus(OrderStatusEnum.WAIT_REGISTER.getValue());
            }else{
                updateEntity.setStatus(OrderStatusEnum.CHECK_ERROR.getValue());
            }
            // 是否要更新推送价格
            if (ObjectUtil.isNotEmpty(apiPushResult.getPriceRight())){
                updateEntity.setPriceAmount(apiPushResult.getPriceRight());

                spePushResut.setPriceAmount(apiPushResult.getPriceRight());
            }
            if (ObjectUtil.isNotEmpty(apiPushResult.getPrice())){
                updateEntity.setOriginAmount(apiPushResult.getPrice());
            }

            memberPushOrderInfoService.updateById(updateEntity);

            MemberPushOrderInfo memberPushOrderInfo = memberPushOrderInfoService.getById(updateEntity.getId());
            spePushResut.setPushOrderInfo(memberPushOrderInfo);

        }finally {
            specialCostomCountInfoService.saveCountInfo(merchantCountDTO);
        }

        // 平台机构协议地址
        // 授权协议信息
//        String protocolUrl = StrUtil.format(protocolHostUrl, pushOrderInfo.getId());
//        spePushResut.setProtocolUrl(protocolUrl);

        // 返回更新结果
        return spePushResut;
    }

    /**
     * 根据订单信息 进件操作
     * @return
     * @throws Exception
     */
    @Override
    @ExceptionLog(key = "#costomId", bizType = "机构检测推送", bizName = "数据检测推送")
    @Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
    public SpePushResut registerUser(String orderNo) throws Exception {

        SpePushResut spePushResut = new SpePushResut();
        spePushResut.setPushSuccess(false);
        MemberPushOrderInfo pushOrderInfo = memberPushOrderInfoMapper.getEnityByIdLock(orderNo);
        if (ObjectUtil.isEmpty(pushOrderInfo)){
            // 信息为空
            spePushResut.setMessage("订单信息为空");
            return spePushResut;
        }

        if (!ObjectUtil.equals(pushOrderInfo.getStatus(), OrderStatusEnum.WAIT_REGISTER.getValue()) &&
                !ObjectUtil.equals(pushOrderInfo.getStatus(), OrderStatusEnum.WAIT_APPROVE.getValue())){
            // 订单状态错误
            spePushResut.setMessage("订单状态错误");
            return spePushResut;
        }

        // 查询用户信息
        SpecialCostomInfo costomInfo = this.baseMapper.getEntryByIdLock(pushOrderInfo.getInfoId());
        MemberExtInfo memberExtInfo = this.memberExtInfoMapper.selectById(pushOrderInfo.getUid());

        // TODO 240829 临时注释协议
        // String protocolHtmlUrl = this.handleProtocolStorge(pushOrderInfo, memberExtInfo);
        // if (StrUtil.isEmpty(protocolHtmlUrl)){
        //     spePushResut.setMessage("保存用户授权协议错误");
        //     return spePushResut;
        // }

        // 构造返回信息
        spePushResut.setInfoId(pushOrderInfo.getInfoId());
        spePushResut.setInfoType(pushOrderInfo.getInfoType());
        spePushResut.setItemInfoId(pushOrderInfo.getTaskId());
        spePushResut.setInfoName(pushOrderInfo.getInfoName());

        // 收益金额
        spePushResut.setPriceAmount(pushOrderInfo.getPriceAmount());

        MerchantCountDTO merchantCountDTO = new MerchantCountDTO(costomInfo.getId().intValue(), costomInfo.getName());
        merchantCountDTO.setRegisterNumber(1);

        try {
            log.info("【机构进件】开始进件【orderNo】{}【infoType】{}", pushOrderInfo.getId());
            ApiPushResult apiPushResult = InfoTypeFactory.getService(costomInfo.getInfoType()).registerUser(costomInfo, pushOrderInfo, memberExtInfo);
            log.info("【机构进件】进件完成【orderNo】{}【apiPushResult】{}", pushOrderInfo.getId(), JSON.toJSONString(apiPushResult));

            spePushResut.setPushSuccess(apiPushResult.isSuccess());
            spePushResut.setSettleFlag(apiPushResult.isSettleFlag());
            spePushResut.setSkipUrl(apiPushResult.getSkipUrl());
            spePushResut.setMessage(apiPushResult.getMessage());

            MemberPushOrderInfo updateEntity = new MemberPushOrderInfo();
            updateEntity.setId(pushOrderInfo.getId());
            updateEntity.setStatus(OrderStatusEnum.FAILED.getValue());
            // 更新订单信息
            if (apiPushResult.isSuccess()){
                merchantCountDTO.setRegisterPassNumber(1);
                updateEntity.setStatus(OrderStatusEnum.SUCCESS.getValue());
            }
            memberPushOrderInfoService.updateById(updateEntity);

            //如果进行结算，
            // 更新账户余额
            if (apiPushResult.isSettleFlag()){
                merchantCountDTO.setSettleNumber(1);
                merchantCountDTO.setSettleAmount(pushOrderInfo.getPriceAmount());

                /**
                 * 机构收益统计
                 */
                CountInfoDTO countInfoDTO = new CountInfoDTO(memberExtInfo.getChannelCode());
                countInfoDTO.setSpePushCount(1);
                countInfoDTO.setSpePushAmount(spePushResut.getPriceAmount());
                countCommonService.calculateDataInfo2(countInfoDTO);

                String billDateInfo = LocalDate.now().toString();

                EntryAccountDTO entryAccountDTO = new EntryAccountDTO();
                entryAccountDTO.setInfoId(String.valueOf(pushOrderInfo.getInfoId()));
                entryAccountDTO.setBillDateInfo(billDateInfo);
                entryAccountDTO.setActionType(ActionTypeEnum.XH.getValue());
                entryAccountDTO.setChangeAmount(BigDecimal.ZERO.subtract(pushOrderInfo.getPriceAmount()));
                entryAccountDTO.setExtData(spePushResut.getExtData());
                entryAccountDTO.setOperatorId("0");
                entryAccountDTO.setOperatorName("system");

                accountItemSpecialService.entryAccountInfo(entryAccountDTO);

                /*************************进件成功之后，给用户发送短信************************/
                UseTypeEnum useTypeEnum = UseTypeEnum.NOTICE;
                String mobile = memberExtInfo.getMobile();
                String operType = "3";

                JSONArray jsonArray = new JSONArray();
                jsonArray.add(memberExtInfo.getUsername());
                // 机构的名称
                jsonArray.add(costomInfo.getCompanyName());

                String ip = "127.0.0.1";
                String appCode = memberExtInfo.getAppCode();
                // 发送短信
                // 进件成功之后，给用户发送短信
                // smsRecordService.sendSms(useTypeEnum, mobile, operType, jsonArray, ip, appCode);
                /*************************进件成功之后，给用户发送短信************************/
            }
        }finally {
            specialCostomCountInfoService.saveCountInfo(merchantCountDTO);
        }

        // 返回更新结果
        return spePushResut;
    }

    @Override
    public String handleProtocolStorge(MemberPushOrderInfo pushOrderInfo, MemberExtInfo memberExtInfo){

        try {
            // 自平台协议
            ChannelInfo channelInfoCache = channelCommonService.getChannelInfoCache(memberExtInfo.getChannelCode());
            ApplicationInfo applicationInfo = applicationInfoService.getAppInfoByType(channelInfoCache.getAppType());
            String apiUrl = applicationInfo.getApiUrl();
            String ownerProtocolUrl = StrUtil.format("{}page/user/newprotocol/{}.html", apiUrl, pushOrderInfo.getId());

            InputStream inputStream = new URL(ownerProtocolUrl).openStream();
            String fileKey = StrUtil.format("approveProtocol/self/{}/{}/{}_用户授权协议.html", pushOrderInfo.getDateInfo(), pushOrderInfo.getId(), pushOrderInfo.getId());
            String ownerProtocolHtmlUrl = uploadProtocol(fileKey, inputStream);

            List<String> protocolUrlList = new ArrayList<>();
            protocolUrlList.add(ownerProtocolHtmlUrl);

            // 第三方授权协议
            if (StrUtil.equals(InfoTypeEnum.APIS.getValue(), pushOrderInfo.getInfoType())){
                MerchantThirdBaseInfo thirdBaseInfo = merchantThirdBaseInfoService.selectEntityByOrderNo(pushOrderInfo.getPushId());
                if (ObjectUtil.isNotEmpty(thirdBaseInfo)){
                    List<MerchantThirdProtocolInfo> thirdProtocolInfoList = merchantThirdProtocolInfoMapper.selectListByThirdId(thirdBaseInfo.getId());
                    Boolean flag = Boolean.TRUE;
                    for (MerchantThirdProtocolInfo protocolInfo : thirdProtocolInfoList) {
                        try {
                            // 上传
                            InputStream inputStream0 = new URL(protocolInfo.getProtocolUrl()).openStream();
                            String fileKey0 = StrUtil.format("approveProtocol/self/{}/{}/third/{}_{}.html", pushOrderInfo.getDateInfo(), pushOrderInfo.getId(), protocolInfo.getId(), protocolInfo.getProtocolName());
                            String itemFileUrl = uploadProtocol(fileKey0, inputStream0);
                            protocolUrlList.add(itemFileUrl);
                        } catch (Exception e) {
                            flag = Boolean.FALSE;
                            log.error("进件协议下载失败, thirdBaseInfoId:{}", thirdBaseInfo.getId());
                            break;
                        }
                    }
                    if (!flag) {
                        // TODO 临时赋值  240828
                        protocolUrlList.add("没有协议");
                    }
                }
            }

            return JSON.toJSONString(protocolUrlList);
        }catch (Exception exception){
            exception.printStackTrace();
        }
        return "";
    }

    public String uploadProtocol(String fileKey, InputStream inputStream) throws Exception {

        OssAuthInfoParam ossAuthInfoParam = new OssAuthInfoParam();

        ossAuthInfoParam.setRegionId(ossAliConfig.getRegionId());
        ossAuthInfoParam.setBucketName(ossAliConfig.getBucketName());
        ossAuthInfoParam.setEndpoint(ossAliConfig.getEndpoint());
        ossAuthInfoParam.setHostUrl(ossAliConfig.getHostUrl());

        ossService.uploadFile(fileKey, inputStream, ossAuthInfoParam);

        String fileUrl = ossAliConfig.getHostUrl() + fileKey;
        return fileUrl;
    }

}
